home *** CD-ROM | disk | FTP | other *** search
- unit AXPropBg;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- ActiveX, AxCtrls;
-
- type
- TActiveXPropBag = class(TActiveXControl, IPersistPropertyBag)
- protected
- { IPersistPropertyBag }
- { Methods should be aliased so they don't collide with existing names }
- function IPersistPropertyBag.InitNew = PersistPropBagInitNew;
- function IPersistPropertyBag.Load = PersistPropBagLoad;
- function IPersistPropertyBag.Save = PersistPropBagSave;
- function PersistPropBagInitNew: HResult; stdcall;
- function PersistPropBagLoad(const pPropBag: IPropertyBag;
- const pErrorLog: IErrorLog): HResult; stdcall;
- function PersistPropBagSave(const pPropBag: IPropertyBag; fClearDirty: BOOL;
- fSaveAllProperties: BOOL): HResult; stdcall;
- end;
-
- implementation
-
- uses
- ComObj;
-
- { Helper Methods }
-
- const
- DispIDArgs: Longint = DISPID_PROPERTYPUT;
-
- function HandleException: HResult;
- var
- E: TObject;
- begin
- E := ExceptObject;
- if (E is EOleSysError) and (EOleSysError(E).ErrorCode < 0) then
- Result := EOleSysError(E).ErrorCode else
- Result := E_UNEXPECTED;
- end;
-
- { GetDispatchPropValue returns the value of the property associated with }
- { Disp's DispID. }
- function GetDispatchPropValue(Disp: IDispatch; DispID: Integer): OleVariant;
- var
- ExcepInfo: TExcepInfo;
- DispParams: TDispParams;
- Status: HResult;
- begin
- FillChar(DispParams, SizeOf(DispParams), 0);
- Status := Disp.Invoke(DispID, GUID_NULL, 0, DISPATCH_PROPERTYGET, DispParams,
- @Result, @ExcepInfo, nil);
- if Status <> S_OK then DispatchInvokeError(Status, ExcepInfo);
- end;
-
- { SetDispatchPropValue sets the value of the property associated with }
- { Disp's DispID. }
- procedure SetDispatchPropValue(Disp: IDispatch; DispID: Integer;
- const Value: OleVariant);
- var
- ExcepInfo: TExcepInfo;
- DispParams: TDispParams;
- Status: HResult;
- begin
- with DispParams do
- begin
- rgvarg := @Value;
- rgdispidNamedArgs := @DispIDArgs;
- cArgs := 1;
- cNamedArgs := 1;
- end;
- Status := Disp.Invoke(DispId, GUID_NULL, 0, DISPATCH_PROPERTYPUT, DispParams,
- nil, @ExcepInfo, nil);
- if Status <> S_OK then DispatchInvokeError(Status, ExcepInfo);
- end;
-
- { EnumDispatchProperties fills a TStrings with property names and }
- { dispids for the properties of Dispatch. You can use PropType and }
- { VTCode to filter for properties of a specific type, or you can pass }
- { GUID_NULL and VT_EMPTY respectively to get all properties. }
- procedure EnumDispatchProperties(Dispatch: IDispatch; PropType: TGUID;
- VTCode: Integer; PropList: TStrings);
- const
- INVOKE_PROPERTYSET = INVOKE_PROPERTYPUT or INVOKE_PROPERTYPUTREF;
- var
- I: Integer;
- TypeInfo: ITypeInfo;
- TypeAttr: PTypeAttr;
- FuncDesc: PFuncDesc;
- VarDesc: PVarDesc;
-
- procedure SaveName(Id: Integer);
- var
- Name: WideString;
- begin
- OleCheck(TypeInfo.GetDocumentation(Id, @Name, nil, nil, nil));
- if PropList.IndexOfObject(TObject(Id)) = -1 then
- PropList.AddObject(Name, TObject(Id));
- end;
-
- function IsPropType(const TypeInfo: ITypeInfo; TypeDesc: PTypeDesc): Boolean;
- var
- RefInfo: ITypeInfo;
- RefAttr: PTypeAttr;
- IsNullGuid: Boolean;
- begin
- IsNullGuid := IsEqualGuid(PropType, GUID_NULL);
- Result := IsNullGuid and (VTCode = VT_EMPTY);
- if Result then Exit;
- case TypeDesc.vt of
- VT_PTR: Result := IsPropType(TypeInfo, TypeDesc.ptdesc);
- VT_USERDEFINED:
- begin
- OleCheck(TypeInfo.GetRefTypeInfo(TypeDesc.hreftype, RefInfo));
- OleCheck(RefInfo.GetTypeAttr(RefAttr));
- try
- Result := IsEqualGUID(RefAttr.guid, PropType);
- if not Result and (RefAttr.typekind = TKIND_ALIAS) then
- Result := IsPropType(RefInfo, @RefAttr.tdescAlias);
- finally
- RefInfo.ReleaseTypeAttr(RefAttr);
- end;
- end;
- else
- Result := IsNullGuid and (TypeDesc.vt = VTCode);
- end;
- end;
-
- function HasMember(const TypeInfo: ITypeInfo; Cnt, MemID, InvKind: Integer): Boolean;
- var
- I: Integer;
- FuncDesc: PFuncDesc;
- begin
- for I := 0 to Cnt - 1 do
- begin
- OleCheck(TypeInfo.GetFuncDesc(I, FuncDesc));
- try
- if (FuncDesc.memid = MemID) and (FuncDesc.invkind and InvKind <> 0) then
- begin
- Result := True;
- Exit;
- end;
- finally
- TypeInfo.ReleaseFuncDesc(FuncDesc);
- end;
- end;
- Result := False;
- end;
-
- begin
- OleCheck(Dispatch.GetTypeInfo(0,0,TypeInfo));
- if TypeInfo = nil then Exit;
- OleCheck(TypeInfo.GetTypeAttr(TypeAttr));
- try
- for I := 0 to TypeAttr.cVars - 1 do
- begin
- OleCheck(TypeInfo.GetVarDesc(I, VarDesc));
- try
- if (VarDesc.wVarFlags and VARFLAG_FREADONLY <> 0) and
- IsPropType(TypeInfo, @VarDesc.elemdescVar.tdesc) then
- SaveName(VarDesc.memid);
- finally
- TypeInfo.ReleaseVarDesc(VarDesc);
- end;
- end;
- for I := 0 to TypeAttr.cFuncs - 1 do
- begin
- OleCheck(TypeInfo.GetFuncDesc(I, FuncDesc));
- try
- if ((FuncDesc.invkind = INVOKE_PROPERTYGET) and
- HasMember(TypeInfo, TypeAttr.cFuncs, FuncDesc.memid, INVOKE_PROPERTYSET) and
- IsPropType(TypeInfo, @FuncDesc.elemdescFunc.tdesc)) or
- ((FuncDesc.invkind and INVOKE_PROPERTYSET <> 0) and
- HasMember(TypeInfo, TypeAttr.cFuncs, FuncDesc.memid, INVOKE_PROPERTYGET) and
- IsPropType(TypeInfo,
- @FuncDesc.lprgelemdescParam[FuncDesc.cParams - 1].tdesc)) then
- SaveName(FuncDesc.memid);
- finally
- TypeInfo.ReleaseFuncDesc(FuncDesc);
- end;
- end;
- finally
- TypeInfo.ReleaseTypeAttr(TypeAttr);
- end;
- end;
-
- { TActiveXPropBag.IPersistPropertyBag }
- function TActiveXPropBag.PersistPropBagInitNew: HResult;
- begin
- // NOTE: A return value of E_NOTIMPL is not allowed. You must return S_OK
- // even if this method does nothing.
- Result := S_OK;
- end;
-
- function TActiveXPropBag.PersistPropBagLoad(const pPropBag: IPropertyBag;
- const pErrorLog: IErrorLog): HResult;
- var
- PropList: TStringList;
- i: Integer;
- WPropName: WideString;
- PropValue: OleVariant;
- begin
- try
- if pPropBag = nil then
- begin
- Result := E_POINTER;
- Exit;
- end;
- Result := S_OK;
- PropList := TStringList.Create;
- try
- EnumDispatchProperties(Self as IDispatch, GUID_NULL, VT_EMPTY, PropList);
- for i := 0 to PropList.Count - 1 do
- begin
- WPropName := PropList[i];
- if pPropBag.Read(PWideChar(WPropName), PropValue, pErrorLog) = S_OK then
- SetDispatchPropValue(Self as IDispatch, Integer(PropList.Objects[i]),
- PropValue);
- end;
- finally
- PropList.Free;
- end;
- except
- Result := HandleException;
- end;
- end;
-
- function TActiveXPropBag.PersistPropBagSave(const pPropBag: IPropertyBag;
- fClearDirty: BOOL; fSaveAllProperties: BOOL): HResult;
- var
- PropList: TStringList;
- i: Integer;
- WPropName: WideString;
- begin
- try
- if pPropBag = nil then
- begin
- Result := E_POINTER;
- Exit;
- end;
- Result := S_OK;
- PropList := TStringList.Create;
- try
- EnumDispatchProperties(Self as IDispatch, GUID_NULL, VT_EMPTY, PropList);
- for i := 0 to PropList.Count - 1 do
- begin
- WPropName := PropList[i];
- pPropBag.Write(PWideChar(WPropName),
- GetDispatchPropValue(Self as IDispatch, Integer(PropList.Objects[i])));
- end;
- finally
- PropList.Free;
- end;
- except
- Result := HandleException;
- end;
- end;
-
- end.
-